﻿using System;
using System.Drawing;
using CanvasControl.Model;
using GraphDrawing.Graph.Model;

namespace GraphDrawing.Graph.Behaviors
{
    /// <summary>
    /// Состояние перемещения одного или нескольких блоков.
    /// </summary>
    public class DraggingStatePresenter : ModelStatePresenter
    {
        /// <summary>
        /// Размеры области, в рамках которой перемещение не будет инициировать перетаскивание.
        /// </summary>
        static readonly Size DRAG_TOLERANCE_SIZE = SystemMetrics.GetDragToleranceSize();

        /// <summary>
        /// Координаты точки, в которой было зафиксировано первое нажатие мыши.
        /// </summary>
        readonly Point clickPoint;

        /// <summary>
        /// Флаг, равный true, если было начато перетаскивание, иначе false.
        /// </summary>
        bool isDragging;

        /// <summary>
        /// Координаты предыдущей точки, в которой находился указатель мыши.
        /// </summary>
        Point previousPoint;

        public DraggingStatePresenter(ModelStateContext context, Point point, BlockModel hitBlock) : base(context)
        {
            clickPoint = previousPoint = point;
            var graph = context.ZOrder;
            if (!hitBlock.IsSelected)
            {
                graph.ClearSelection();
                graph.Select(hitBlock);
            }
            graph.BringToFront(hitBlock);
        }

        public override void OnMouseMove(Point p)
        {
            var viewPoint = context.CanvasModel.ViewPort.ClientToGlobal(p);
            if (isDragging || (isDragging = ShouldStartDrag(viewPoint)))
                DoDrag(viewPoint);
            previousPoint = viewPoint;
        }

        /// <summary>
        /// Выполняет перетаскивание.
        /// </summary>
        /// <param name="viewPoint">Координаты курсора в системе координат представления.</param>
        void DoDrag(Point viewPoint)
        {
//            foreach (var block in context.Graph.GetSelectedBlocks())
//                block.Position = .Offset(viewPoint.X - previousPoint.X, viewPoint.Y - previousPoint.Y);
            context.Canvas.UpdateView();
        }

        /// <summary>
        /// Определяет, должно ли начаться перетаскивание при перемещении курсора мыши.
        /// </summary>
        /// <param name="viewPoint">Текущие координаты курсора в системе координат представления.</param>
        /// <returns>Возвращает true, если перетаскивание должно начаться, иначе false.</returns>
        bool ShouldStartDrag(Point viewPoint)
        {
            return Math.Abs(clickPoint.X - viewPoint.X) >= DRAG_TOLERANCE_SIZE.Width || (Math.Abs(clickPoint.Y - viewPoint.Y) >= DRAG_TOLERANCE_SIZE.Height);
        }
    }
}